﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Text;
using System.Threading.Tasks;
using XQ.WeChatOfficialAccount.DAL;
using System.Data.Entity.Core.Objects;

namespace XQ.WeChatOfficialAccount.DAL.DAL
{
    /// <summary>
    /// 通用dal
    /// 实现了增删改查基本功能。
    /// </summary>
    /// <typeparam name="T">dal所对应的model</typeparam>
    public abstract class BaseDal<T> : IDisposable
        where T : class,new()
    {
        /// <summary>
        /// 实体
        /// </summary>
        protected readonly WeChatOfficialAccountEntities db = new WeChatOfficialAccountEntities();
        public BaseDal()
        {
            //
        }

        /// <summary>
        /// 原始数据查询
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        public IEnumerable<T> SqlQuery(string sql, params object[] param)
        {
            IEnumerable<T> query = db.Database.SqlQuery<T>(sql, param);
            return query;
        }

        /// <summary>
        /// 原始sql命令
        /// </summary>
        public int SqlCommand(string sql, params object[] param)
        {
            return db.Database.ExecuteSqlCommand(sql, param);
        }

        public IEnumerable<T> Where(Func<T, bool> express)
        {
            return db.Set<T>().Where(express);
        }

        public int ModelCount(Func<T, bool> express)
        {
            return db.Set<T>().Count(express);
        }

        public bool ExistModel(Func<T, bool> express)
        {
            return ModelCount(express) > 0;
        }

        /// <summary>
        /// 添加模型
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public T AddModel(T model)
        {
            T newModel = db.Set<T>().Add(model);
            db.SaveChanges();
            return newModel;
        }

        /// <summary>
        /// 批量添加模型
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public int AddModels(List<T> models)
        {
            if (models != null && models.Count > 0)
            {
                models.ForEach(delegate (T model)
                 {
                     db.Set<T>().Add(model);
                 });
            }
            return db.SaveChanges();
        }

        /// <summary>
        /// 批量添加模型
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public int AddRangeModels(List<T> models)
        {
            if (models != null && models.Count > 0)
            {
                db.Set<T>().AddRange(models);
            }
            return db.SaveChanges();
        }

        /// <summary>
        /// 批量添加模型（第三方插件Z.EntityFramework.Extensions）
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public int BulkInsertRangeModels(List<T> models)
        {
            if (models != null && models.Count > 0)
            {
                db.BulkInsert(models);
            }
             db.BulkSaveChanges();
            return models.Count;
        }


        /// <summary>
        /// 更新模型
        /// </summary>
        /// <param name="express">更新条件</param>
        /// <param name="updateHandler">更新model的方法</param>
        /// <returns></returns>
        public int UpdateModel(Func<T, bool> express, Func<T, T> updateHandler)
        {
            if (updateHandler == null) { return 0; }
            //
            //IQueryable<T> query= db.Set<T>().Where(express).AsQueryable<T>();
            
            //
            db.Set<T>().Where(express).ToList().ForEach(delegate(T model)
            {
                model = updateHandler.Invoke(model);
            });
            return db.SaveChanges();
        }

        /// <summary>
        /// 批量更新模型（第三方插件Z.EntityFramework.Extensions）
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public int BulkUpdateRangeModels(List<T> models)
        {
            if (models != null && models.Count > 0)
            {
                db.BulkUpdate(models);
            }
            db.BulkSaveChanges();
            return models.Count;
        }

        /// <summary>
        /// 直接更新实体模型
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int UpdateModel(T model)
        {
            if (model != null)
            {
                Exists(model);
                db.Entry<T>(model).State = EntityState.Modified;
            }
            return db.SaveChanges();
        }

        /// <summary>
        /// 查询单个
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public T FindModel(Func<T, bool> express)
        {
            return db.Set<T>().FirstOrDefault(express);
        }

        /// <summary>
        /// 查询多个
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public List<T> FindAllModel(Func<T, bool> express, int start = -1, int count = -1)
        {
            IEnumerable<T> query = db.Set<T>().Where(express);
            if (start >= 0 && count >= 0)
            {
                query = query.Skip(start).Take(count);
            }
            return query.ToList();
        }

        /// <summary>
        /// 删除多个模型
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public int DeleteModel(Func<T, bool> express)
        {
            db.Set<T>().Where(express).ToList().ForEach(delegate(T model)
            {
                db.Set<T>().Remove(model);
            });
            return db.SaveChanges();
        }

        /// <summary>
        /// 删除多个模型
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public int DeleteRangeModel(Func<T, bool> express)
        {
            db.Set<T>().RemoveRange(db.Set<T>().Where(express));
            return db.SaveChanges();
        }

        /// <summary>
        /// 批量删除模型（第三方插件Z.EntityFramework.Extensions）
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public int BulkDeleteModel(List<T> models)
        {
            if (models != null && models.Count > 0)
            {
                db.BulkDelete(models);
            }
            db.BulkSaveChanges();
            return models.Count;
        }

        public void Dispose()
        {
            db.Dispose();
        }

        /// <summary>
        /// 如果上下文中存在对象则移除
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Exists(T entity)
        {
            ObjectContext _ObjContext = ((IObjectContextAdapter)db).ObjectContext;
            ObjectSet<T> _ObjSet = _ObjContext.CreateObjectSet<T>();
            var entityKey = _ObjContext.CreateEntityKey(_ObjSet.EntitySet.Name, entity);

            Object foundEntity;
            var exists = _ObjContext.TryGetObjectByKey(entityKey, out foundEntity);
            // TryGetObjectByKey attaches a found entity
            // Detach it here to prevent side-effects
            if (exists)
            {
                _ObjContext.Detach(foundEntity);
            }
            return (exists);
        }
    }
}
